/*
 * Copyright (c) 2010, okazoh_tk. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <string.h>
#include "alkes/testdriver/String.h"

namespace alkes {

#if (ALKES_API_WIN32 == 1)
#if !defined(__GNUC__)
#define alkes_sprintf(dst, dst_len, fmt, ...)   sprintf_s(dst, dst_len, fmt, __VA_ARGS__)
#else
#define alkes_sprintf(dst, dst_len, fmt, ...)   sprintf_s(dst, dst_len, fmt, ## __VA_ARGS__)
#endif
#define alkes_strcpy(dst, dst_len, src)         strcpy_s(dst, dst_len, src)
#define int64_fmt       "%I64d"
#define uint64_fmt      "%I64u"
#define uint64_fmt_x    "%#08I64x"
#else
#if !defined(__GNUC__)
#define alkes_sprintf(dst, dst_len, fmt, ...)   snprintf(dst, dst_len, fmt, __VA_ARGS__)
#else
#define alkes_sprintf(dst, dst_len, fmt, ...)   snprintf(dst, dst_len, fmt, ## __VA_ARGS__)
#endif
#define alkes_strcpy(dst, dst_len, src)         strncpy(dst, src, dst_len-1); dst[dst_len-1] = '\0'
#define int64_fmt       "%lld"
#define uint64_fmt      "%llu"
#define uint64_fmt_x    "%#08llx"

//#if (defined(__x86_64__) && __x86_64__ == 1) || (defined(__LP64__) && __LP64__ == 1)
#if (__SIZEOF_POINTER__ == 8)
#else
#endif

#endif

    
String::String(bool v)
{
    if (v)
    {
        alkes_strcpy(buffer_, BUF_LENGTH, "true");
    }
    else
    {
        alkes_strcpy(buffer_, BUF_LENGTH, "false");
    }
}

String::String(int8_t v)
{
    alkes_sprintf(buffer_, BUF_LENGTH, "%d", (int32_t)v);
}

String::String(uint8_t v)
{
    alkes_sprintf(buffer_, BUF_LENGTH, "%u(%#02x)", (uint32_t)v, (uint32_t)v);
}

String::String(int16_t v)
{
    alkes_sprintf(buffer_, BUF_LENGTH, "%d", (int32_t)v);
}

String::String(uint16_t v)
{
    alkes_sprintf(buffer_, BUF_LENGTH, "%u(%#04x)", (uint32_t)v, (uint32_t)v);
}

String::String(int32_t v)
{
    alkes_sprintf(buffer_, BUF_LENGTH, "%d", v);
}

String::String(uint32_t v)
{
    alkes_sprintf(buffer_, BUF_LENGTH, "%u(%#08x)", v, v);
}

String::String(int64_t v)
{
    alkes_sprintf(buffer_, BUF_LENGTH, int64_fmt, v);
}

String::String(uint64_t v)
{
    alkes_sprintf(buffer_, BUF_LENGTH, uint64_fmt "(" uint64_fmt_x ")", v, v);
}

String::String(float v)
{
    alkes_sprintf(buffer_, BUF_LENGTH, "%f", v);
}

String::String(double v)
{
    alkes_sprintf(buffer_, BUF_LENGTH, "%f", v);
}

String::String(const void* v)
{
    alkes_sprintf(buffer_, BUF_LENGTH, "%p", v);
}

String::String(const Vector2D& v)
{
    String x(v.x);
    String y(v.y);
    alkes_sprintf(buffer_, BUF_LENGTH, "Vector2D(%s,%s)", x.c_str(), y.c_str());
}

String::String(const Point2D& v)
{
    String x(v.x);
    String y(v.y);
    alkes_sprintf(buffer_, BUF_LENGTH, "Point2D(%s,%s)", x.c_str(), y.c_str());
}

String::String(const Rect& v)
{
    String x(v.x);
    String y(v.y);
    String w(v.width);
    String h(v.height);
    alkes_sprintf(buffer_, BUF_LENGTH, "Rect(%s,%s,%s,%s)",
        x.c_str(), y.c_str(), w.c_str(), h.c_str());
}

String::String(const Color& v)
{
    String r(v.r);
    String g(v.g);
    String b(v.b);
    String a(v.a);
    alkes_sprintf(buffer_, BUF_LENGTH, "Color(%s,%s,%s,%s)",
        r.c_str(), g.c_str(), b.c_str(), a.c_str());
}

String::~String()
{
}

const char* String::c_str() const
{
    return buffer_;
}

void String::initAsData(const void* v, int32_t length)
{
    if (8 < length)
        length = 8;

    static const char chars[16] = {
        '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
    };

    char* dst = buffer_;
    int32_t remain = BUF_LENGTH;
    int32_t i;
    const uint8_t* p = (const uint8_t*)v;
    for (i = 0; i < length && 3 < remain; ++i, ++p, remain -= 3)
    {
        *(dst  ) = chars[(*p >> 4) & 0xf];
        *(dst+1) = chars[(*p     ) & 0xf];
        *(dst+2) = ' ';
        dst += 3;
    }
    *dst = '\0';
}

}
